package ac.uk.qmul.gemom.scenario;

import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Label;
import java.awt.TextArea;
import java.awt.TextField;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemListener;
import java.awt.event.InputEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.Vector;

import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.JSplitPane;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.ListSelectionModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.table.TableModel;
import javax.swing.text.DefaultCaret;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import javax.swing.JCheckBox;

import com.qsphere.boundary.gemom.GEMOMBrokerAdapter;
import com.qsphere.boundary.gemom.GEMOMClientData;
import com.qsphere.boundary.gemom.GEMOMData;
import com.qsphere.boundary.gemom.GEMOMListener;
import com.qsphere.boundary.gemom.GEMOMMessageType;
import com.qsphere.boundary.gemom.GEMOMParameters;
import com.qsphere.boundary.gemom.impl.GEMOMBrokerAdapterImpl;


/*
* COPYRIGHT DISCLAIMER
* Synopsis: All the source codes presented in this document are intellectual
* properties of Queen Mary, University of London.
* 
* @year 2010
* @author Peng Jiang, John Bigham, Jiayi Wu Jinfu Wang------------QMUL
* @version 1.0 
*/
public class FaultManager extends JFrame implements ActionListener, GEMOMListener, ItemListener  {

	private static final String PUBLISH = "publish";
	private static final String SUBSCRIBE = "subscribe";
	private static final String RENAME = "rename";
	private static final String DELETE = "delete";
	private static final String MOVE_TOPIC = "moveTopic";
	private static final String NAMESPACE_SUBSCRIBE = "namespaceSubscribe";
	private static final String NAMESPACE_RENAME = "namespaceRename";
	private static final String NAMESPACE_MOVE = "namespaceMove";
	private static final String NAMESPACE_DELETE = "namespaceDelete";
	private static final String CONNECT = "connect";
	private static final String DISCONNECT = "disconnect";
	private static final String AUTO_SUBSCRIBE = "autoSubscribe";
	
	private static final String OPTION_SUBSCRIBE = "optionSubscribe";
	private static final String OPTION_UNSUBSCRIBE = "optionUnsubscribe";
	
	private static final String START="start";
	private static final String STOP="stop";
	
	private static final String START_SUBSCRIBER="start";
	private static final String STOP_SUBSCRIBER="stop";
	
	private static final String SWITCH_ON = "counter on";
	
	private static final String SWITCH_OFF = "counter off";
	
	private int id; 

	private static final int NAMESPACE_LABEL_WIDTH = 140;
	private static final int NAMESPACE_FIELD_X = NAMESPACE_LABEL_WIDTH + 15;
	private static final int SECOND_COLUMN_FIELD_WIDTH = 125;
	private static final int SECOND_COLUMN_LABEL_X = 220;
	private static final int SECOND_COLUMN_LABEL_WIDTH = 120;
	private static final int SECOND_COLUMN_FIELD_X = SECOND_COLUMN_LABEL_X
			+ SECOND_COLUMN_LABEL_WIDTH;

	private static final int TITLE_HEIGHT = 25;

	protected static final String VOLUMETRY_TEST_TOPIC = "__FAST1";
	protected boolean m_showVolumetryMonitorMessages = true;
	protected int m_updateCounter = 0;
	protected int m_volumetryTestPublishCount = 100;

	protected GEMOMBrokerAdapter m_broker = null;

	// Demo GUI controls
	protected TextField[] m_fieldNameFields = new TextField[4];
	protected TextField[] m_fieldValueFields = new TextField[4];
	protected TextField m_topicField = new TextField();
	protected TextField m_namespaceField = new TextField();
	protected TextField m_subscribeTopicField = new TextField();
	protected TextField m_namespaceSubscribeTopicField = new TextField();

	protected TextField m_renameTopicField = new TextField();
	protected TextField m_namespaceRenameTopicField = new TextField();
	protected TextField m_newTopicField = new TextField();
	// protected TextField m_namespaceNewTopicField = new TextField();

	protected TextField m_deleteTopicField = new TextField();
	protected TextField m_namespaceDeleteTopicField = new TextField();

	protected TextField m_namespaceSubscribeField = new TextField();
	protected TextField m_namespaceRenameField = new TextField();
	protected TextField m_namespaceNewField = new TextField();
	protected TextField m_namespaceDeleteField = new TextField();

	protected TextField m_moveTopicField = new TextField();
	protected TextField m_sourceNamespaceMoveTopicField = new TextField();
	protected TextField m_destinationNamespaceMoveTopicField = new TextField();

	protected TextField m_namespaceMoveField = new TextField();
	protected TextField m_namespaceMoveDestinationField = new TextField();

	protected JTextArea m_monitorAllSubArea = new JTextArea();
	protected JTextArea m_monitorSubArea = new JTextArea();
	protected JTextArea m_monitorMainArea = new JTextArea();

	protected DateFormat m_sdf = SimpleDateFormat
			.getTimeInstance(SimpleDateFormat.MEDIUM);
	
	private Button connectButton;
	private Button disconnectButton;
	private Button autosubButton;
	private Button subscribeButton;
	private Button unsubscribeButton;
	
	private Button startSubscriberButton;
	private Button stopSubscriberButton;
	
	private JCheckBox counterOnBox;
	
	private JCheckBox counterOffBox;
	
	private boolean m_isConnected = false;

	private JTree tree;
	
    protected JSplitPane splitPane, mainSplitPane;
    
    protected JScrollPane scrollMainMonitor = new JScrollPane();
    protected JScrollPane scrollNsMonitor = new JScrollPane();
    protected JScrollPane scrollNsTree = new JScrollPane();
    protected JScrollPane scrollSubMonitor = new JScrollPane();
    
	protected TextField subIpString= new TextField();
	protected TextField subPortString= new TextField();
	
	protected TextField pubIpString= new TextField();
	protected TextField pubPortString= new TextField();
	
	protected TextField namespaceField= new TextField();
	protected TextField topicField= new TextField();
 	
	public double time_start;
	public double time_stop;
	
	public int tSeg_index = 0;
	
	private Subscription subscription;
	
	private String[] updateStrings = {"", ""}; 
	
	// Code Map:   0 - Update All Namespace & Topics; 1 - Update Selected Namespace; 2 - Update Selected Topic
	private int updateCode = -1;
	
	private boolean m_publishToSystemOut = false;
	
	private GEMOMParameters connectParameters;
	
	private boolean shouldStop = false;
	
	private DelayScheduler delayScheduler;

	// private String m_psProxyIP;

	public FaultManager(int demoId, Subscription sub) {
		
		this.id = demoId;
		
		this.subscription = sub;
		
		setTitle("FaultManager " + id);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		initialiseStartupParameters();

		JPanel panel = new JPanel();
		
		panel.setLayout(new BorderLayout());
		
		this.setBounds(10, 10, 1000, 600);
		this.setLayout(new GridLayout(1, 2));
		
		panel.setBounds(10, 10, 600, 600);

		DefaultMutableTreeNode top = new DefaultMutableTreeNode("All namespaces");
		tree = new JTree(top);

	    tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

		tree.addMouseListener(new MouseAdapter() {
			public void mousePressed(MouseEvent event) {
				if (((event.getModifiers() & InputEvent.BUTTON3_MASK) != 0)
						&& (tree.getSelectionCount() > 0)) {
					//showMenu(event.getX(), event.getY());
				}
			}
		});
		
		tree.addTreeSelectionListener(new TreeSelectionListener () {
			public void valueChanged(TreeSelectionEvent e) {
				//TreePath path = e.getPath();
				//String text = path.getPathComponent(path.getPathCount() - 1).toString();
				//String text=Datasaver.pathtransfer(path.toString());
				//textField.setText(text);
				
			    DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();

			    String rootName = tree.getModel().getRoot().toString();
			    
                if (node == null){
                //Nothing is selected.
                    setUpdateSetting(false, null, null);
                    return;
                }

                Object nodeInfo = node.getUserObject();
                // topic or namespace selected
                
                //printLineInSubMonitor("selected node = " + (String)nodeInfo);
                //printLineInSubMonitor("parent node = " + node.getParent().toString());
                
                if(!node.isRoot()){
                    if (node.isLeaf()){
                	    // topic is selected
                	    if (!node.getParent().toString().equalsIgnoreCase(rootName)){
                            String topicName = (String)nodeInfo;
                            setUpdateSetting(false, node.getParent().toString(), topicName);
                	    }
                	     //A particular namespace selected
                	    else{
                    	    String nsName = (String)nodeInfo;
                    	    setUpdateSetting(false, nsName, "");
                	    }
                	    return;
                    }
                }
                //All namespace selected
                else{
                	setUpdateSetting(true, "", "");
                }
               
			}
		});
		
		//textField.setEditable(false);
		scrollMainMonitor.getViewport().add(m_monitorMainArea);

		// always update the text field view point
		DefaultCaret caret = (DefaultCaret)m_monitorMainArea.getCaret();
		caret.setUpdatePolicy(DefaultCaret.ALWAYS_UPDATE);

		scrollMainMonitor.setPreferredSize(new Dimension(500, 100));

		scrollNsTree.getViewport().add(tree);
		
		splitPane= new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollMainMonitor, scrollNsTree);
		splitPane.setOneTouchExpandable(true);
		splitPane.setDividerLocation(150);
		
		//getContentPane().setLayout(new FlowLayout());
		
		panel.add(splitPane, "Center");
		
		// set up the connection panel
		JPanel conPanel= new JPanel(new GridLayout(7, 2));

		Label l1 = new Label("Subscription Broker IP", Label.CENTER);
		Label l2= new Label("Subscription Broker Port", Label.CENTER);

		conPanel.add(l1);
		conPanel.add(subIpString);

		conPanel.add(l2);
		conPanel.add(subPortString);
		
		Label l11 = new Label("Publish Broker IP", Label.CENTER);
		Label l12 = new Label("Publish Broker Port", Label.CENTER);
		
		startSubscriberButton = new Button("Start subscriber");
		startSubscriberButton.setActionCommand(START_SUBSCRIBER);
		startSubscriberButton.addActionListener(this);
		conPanel.add(startSubscriberButton);

		stopSubscriberButton = new Button("Stop subscriber");
		stopSubscriberButton.setActionCommand(STOP_SUBSCRIBER);	
		stopSubscriberButton.addActionListener(this);
		conPanel.add(stopSubscriberButton);
		
		this.startSubscriberButton.setEnabled(true);
		this.stopSubscriberButton.setEnabled(false);
		
		conPanel.add(l11);
		conPanel.add(pubIpString);

		conPanel.add(l12);
		conPanel.add(pubPortString);
		
		connectButton = new Button("Connect");
		connectButton.setActionCommand(CONNECT);
		connectButton.addActionListener(this);
		conPanel.add(connectButton);
		
		disconnectButton = new Button("Disconnect");
		disconnectButton.setActionCommand(DISCONNECT);	
		disconnectButton.addActionListener(this);
		conPanel.add(disconnectButton);
		
		autosubButton = new Button("Auto Subscribe");
		autosubButton.setActionCommand(AUTO_SUBSCRIBE);	
		autosubButton.addActionListener(this);
		conPanel.add(autosubButton);

		panel.add(conPanel,"North");

		// set up the subscriber panel
		JPanel sPanel= new JPanel(new GridLayout(3, 3));

		Label l3 = new Label("Namespace", Label.CENTER);
		Label l4= new Label("Topic", Label.CENTER);

		sPanel.add(l3);
		sPanel.add(namespaceField);

		sPanel.add(l4);
		sPanel.add(topicField);
		
		subscribeButton= new Button("Subscribe");
		subscribeButton.setActionCommand(OPTION_SUBSCRIBE);
		subscribeButton.addActionListener(this);
		sPanel.add(subscribeButton);

		unsubscribeButton= new Button("Unsubscribe");
		unsubscribeButton.setActionCommand(OPTION_UNSUBSCRIBE);
		unsubscribeButton.addActionListener(this);
		sPanel.add(unsubscribeButton);

		panel.add(sPanel,"South");

		// setup the connection Tbalepanel
		JPanel TabPanel = new JPanel( new GridBagLayout() );
		JLabel GTableTitle = new JLabel(  "Gbroker IP"  );
		JLabel STableTitle = new JLabel(  "Connect state" );
		
		JPanel panel2 = new JPanel();
		panel2 = new JPanel(new BorderLayout());
		panel2.setBounds(610, 10, 380, 600);
		
		scrollNsMonitor.getViewport().add(m_monitorAllSubArea);
		
		scrollSubMonitor.getViewport().add(m_monitorSubArea);

		
		mainSplitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollNsMonitor, scrollSubMonitor);
		mainSplitPane.setOneTouchExpandable(true);
		mainSplitPane.setDividerLocation(300);
		
		//panel.add(mainSplitPane, "East");
		//mainSplitPane.setBounds(width, 0, width, height);
		//getContentPane().add(mainSplitPane);
		panel2.add(mainSplitPane, "Center");
		
		JPanel radioPanel= new JPanel(new GridLayout(1, 1));
		
		
		//In initialization code:
	    counterOnBox = new JCheckBox("Switch on delay report");
	    counterOnBox.setMnemonic(KeyEvent.VK_O); 
	    counterOnBox.setSelected(true);

	    //Register a listener for the check boxes.
	    counterOnBox.addItemListener(this);
	    
		radioPanel.add(counterOnBox);
		
		panel2.add(radioPanel,"North");
		
		
		getContentPane().add(panel);
		getContentPane().add(panel2);	

		validate();
		
		//printLineInMonitor(getTimeAsString() + ": Controls ready");
		
		//connect();
		
		//initSubscribe();
	}

	/**
	 * update GEMOMDemo obj with a TimeSeg in PubConfig.tsegs 
	 * @param ts
	 */
	public void updateGEMOMDemo(TimeSeg ts){
		time_start = ts.time_start;
		time_stop = ts.time_stop;
	}
	
	protected void initialiseStartupParameters() {
		// initialize startup parameters
		// m_psProxyIP = getStartupParameter("PSProxyAddress");
		// setUserName(getStartupParameter("Username"));
		// try {
		// m_showVolumetryMonitorMessages = Boolean
		// .parseBoolean(getStartupParameter("VolumetryTestShowMonitorMessages"));
		// } catch (Exception e) {
		// }
		// try {
		// m_volumetryTestPublishCount = Integer
		// .parseInt(getStartupParameter("VolumetryTestIterationCount"));
		// } catch (Exception e) {
		// }
	}

	public void actionPerformed(ActionEvent actionEvent) {
		String command = actionEvent.getActionCommand();
		debug("Action command: " + command + " isNamespace subscribe: "
				+ NAMESPACE_SUBSCRIBE.equals(command));
		if (PUBLISH.equalsIgnoreCase(command)) {
			checkIfConnected();
			onPublish();
		} else if (SUBSCRIBE.equalsIgnoreCase(command)) {
			checkIfConnected();
			onSubscribe();
		} else if (RENAME.equalsIgnoreCase(command)) {
			checkIfConnected();
			onRename();
		} else if (MOVE_TOPIC.equalsIgnoreCase(command)) {
			checkIfConnected();
			onMoveTopic();
		} else if (DELETE.equalsIgnoreCase(command)) {
			checkIfConnected();
			onDelete();
		} else if (NAMESPACE_SUBSCRIBE.equalsIgnoreCase(command)) {
			checkIfConnected();
			onNamespaceSubscribe();
		} else if (NAMESPACE_RENAME.equalsIgnoreCase(command)) {
			checkIfConnected();
			onNamespaceRename();
		} else if (NAMESPACE_MOVE.equalsIgnoreCase(command)) {
			checkIfConnected();
			onNamespaceMove();
		} else if (NAMESPACE_DELETE.equalsIgnoreCase(command)) {
			checkIfConnected();
			onNamespaceDelete();
		} else if (CONNECT.equalsIgnoreCase(command)) {
			if(checkIfAddressGiven())
			    onConnect(pubIpString.getText(), pubPortString.getText());
		} else if (DISCONNECT.equalsIgnoreCase(command)) {
			onDisconnect();
		} else if (AUTO_SUBSCRIBE.equalsIgnoreCase(command)) {
			checkIfConnected();
			initSubscribe();
		} else if (OPTION_SUBSCRIBE.equalsIgnoreCase(command)) {
			checkIfConnected();
			onOptionSubscribe();
		} else if (OPTION_UNSUBSCRIBE.equalsIgnoreCase(command)) {
			checkIfConnected();
			onOptionUnsubscribe();
		} else if (START_SUBSCRIBER.equalsIgnoreCase(command)) {
			if(checkIfAddressGiven()){
				// connecting to a broker to publish before subscribing to any
				checkIfConnected();
				onConnect(pubIpString.getText(), pubPortString.getText());
			    onStartSubscriber(subIpString.getText(), subPortString.getText());
			}
		} else if (STOP_SUBSCRIBER.equalsIgnoreCase(command)) {
			onStopSubscriber();
			
		} else if (SWITCH_ON.equalsIgnoreCase(command)) {
			onSwitchCounter(true);
			
		} else if (SWITCH_OFF.equalsIgnoreCase(command)) {
			onSwitchCounter(false);
		}		
	}

	private void checkIfConnected() {
		if (!m_isConnected) {
			boolean shouldConnect = JOptionPane
					.showConfirmDialog(
							this,
							"You're not connected to GEMOM. Do you want to connect first?",
							"Not Connected", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION;
			if (shouldConnect && checkIfAddressGiven()) {
				onConnect(pubIpString.getText(), pubPortString.getText());
				//connect();
			}
		}
	}
	
	private boolean checkIfAddressGiven() {
		String ip = subIpString.getText();
		String port = subPortString.getText();
		String ip2 = pubIpString.getText();
		String port2 = pubPortString.getText();
		
		if (ip != null && !ip.equalsIgnoreCase("") &&
			port != null && !port.equalsIgnoreCase("") &&
			ip2 != null && !ip2.equalsIgnoreCase("") &&
			port2 != null && !port2.equalsIgnoreCase("") ) {
			
	      return true;
		}
		else{
			 JOptionPane.showMessageDialog(this,
		               "Source broker address and port not specififed", "Error Message",
		               JOptionPane.INFORMATION_MESSAGE);
			return false;
		}
	}
	
	private void initScheduler(){
		if(delayScheduler == null){
			delayScheduler = new DelayScheduler(this);
		}
		if(!delayScheduler.isAlive()){
			delayScheduler.reset();
			delayScheduler.start();
		}
		else{
			delayScheduler.stop();
			delayScheduler.reset();
			delayScheduler.start();
		}
	}
	
	private void onStartSubscriber(String ip, String port){
		
		final Subscription tempSub = subscription;
		final String tempIp = ip;
		final String tempPort = port;
		
		this.shouldStop = false;
		this.startSubscriberButton.setEnabled(false);
		this.stopSubscriberButton.setEnabled(true);
		
		initScheduler();
		
        new Thread()
        {
          public void run()
          {
      		String command="java -jar SimpleSubscriber.jar";
      		command = command + " " + tempIp + " " + tempPort;
      	
      		Set keys = tempSub.getAllNamespace().keySet();
    		int i = 0;
    		Iterator it = keys.iterator();
    		String ns = "";
    		while (it.hasNext()) {
    			ns = ns + it.next().toString() + "/";
    			i++;
    		}   		
    		if(ns.endsWith("/")){
    			ns = ns.substring(0, ns.length()-1);
    		}
    		command = command + " " +ns;
 
    		try {
    			Process p;
    			p = Runtime.getRuntime().exec(command);
    			
    			printLineInMonitor("Starting subscription process");
    			
    			String line = null;
    			String previousLine = "";
    			BufferedReader br = new BufferedReader
    			    (new InputStreamReader(p.getInputStream()));
    			try {

    				while (!this.isInterrupted() &&
    						(line = br.readLine()) != null &&
    						   !clientSaidStop())
    				{ 
    					readThenSchedule(line, previousLine); 
    					// The same line might be read again, so double-check to make sure
    					// same entry doesn't get processed twice
    					if(line.startsWith("!!!"))
    					    previousLine = line;
    					//printLineInMonitor("line is " + line);
    				
    				}
					delayScheduler.turnOff();
    			}
    			catch (IOException e) {
    				e.printStackTrace();
    			}
    			finally {
    				try {
    					br.close();
    				}
    				catch (IOException e) {
    				}
    			}
    			if (this.isInterrupted())
    				printLineInMonitor("*** subscription to the broker source is canceld ***");
    			
    			p.destroy();
    			printLineInMonitor("Subscription to first broker finished without error");
    		}
    		catch (Exception e) {
    			e.printStackTrace();
    		}
          }
        }
        .start
          ();

	}
	
	private void onStopSubscriber(){
		this.shouldStop = true;
		this.startSubscriberButton.setEnabled(true);
		this.stopSubscriberButton.setEnabled(false);
		
		printLineInMonitor("Client issued stop subscription command");

	}
	
	private boolean clientSaidStop(){
	    return this.shouldStop;
	}
	
	
	// read data and publish them using the fault model, such as introducing delays
	private void readThenSchedule(String line, String previousLine){
		 
		if(line.startsWith("!!!") && !line.equalsIgnoreCase(previousLine) ){
			line = line.substring(4, line.length());
			String[] all = line.split("/");
			String ns, topic;
			ns = all[0];
			topic = all [1];
			GEMOMData data = new GEMOMData();
			for(int i = 2; i < all.length; i++){
				String[] pair = all[i].split("="); 
				String fieldName = pair[0];
				if (fieldName.equalsIgnoreCase("")) {
					continue;
				}
				String fieldValue = pair[1];
				data.put(fieldName, fieldValue);
			}
			 
			this.delayScheduler.registerEvent(ns, topic, data);
			
		}
	}


	// connect to publish broker 
	private void onConnect(String ip, String port ) {
		
		this.setConnectionParameters(ip, port);

		if (getGEMOMBrokerInterface().connect("TestinJNI", null,
				connectParameters, null, null)) {
			setIsConnected(true);
		} else {
			JOptionPane.showMessageDialog(this, "Can't connect", "Error",
					JOptionPane.ERROR_MESSAGE);
		}
	}
	
	// ocnnect to publish broker
	private void connect() {
		GEMOMParameters parameters = new GEMOMParameters();
	
		if (getGEMOMBrokerInterface().connect("TestinJNI", this,
				parameters, null, null)) {
			setIsConnected(true);
		} else {
			JOptionPane.showMessageDialog(this, "Can't connect", "Error",
					JOptionPane.ERROR_MESSAGE);
		}
	}

	private void onDisconnect() {
		if (getGEMOMBrokerInterface().disconnect(this, null, null)) {
			setIsConnected(false);
		} else {
			JOptionPane.showMessageDialog(this, "Can't disconnect", "Error",
					JOptionPane.ERROR_MESSAGE);
		}
	}

	private void setIsConnected(boolean isConnected) {
		m_isConnected = isConnected;
		connectButton.setEnabled(!isConnected);
		disconnectButton.setEnabled(isConnected);
		if (isConnected)
			printLineInMonitor(getTimeAsString() + ": Connected");
		else
			printLineInMonitor(getTimeAsString() + ": Disconnected");
	}
	
	public void setPublishToSystemOut(boolean systemOut) {
		this.m_publishToSystemOut = systemOut;
	}
	
	private void setConnectionParameters(String ip, String port) {
		this.connectParameters = new GEMOMParameters();
		connectParameters.put("ConnectionString", "client@"+ip+":"+port);
	}
	
	protected void onSwitchCounter(boolean option){
	    if(delayScheduler != null){
	    	delayScheduler.enableCounter(option);
	    }
	}
	

	/**
	 * Performs publish of data entered by user
	 */
	protected void onPublish() {
		
		String namespace = m_namespaceField.getText();
		String topic = m_topicField.getText();
		if (topic == null || topic.equalsIgnoreCase("")) {
			return;
		}
		if (VOLUMETRY_TEST_TOPIC.equalsIgnoreCase(topic)) {
			startVolumetryTest(topic);
		} else {
			GEMOMData data = new GEMOMData();
			for (int i = 0; i < 4; i++) {
				String fieldName = m_fieldNameFields[i].getText();
				if (fieldName.equalsIgnoreCase("")) {
					continue;
				}
				String fieldValue = m_fieldValueFields[i].getText();
				data.put(fieldName, fieldValue);
			}
			// getGEMOMBrokerInterface().publish(this, topic, data, null);
			getGEMOMBrokerInterface().publish(null, namespace, topic, data,
					null, null);
			printLineInMonitor(getTimeAsString() + ": Publishing on " + topic
					+ " , data:");
			printLineInMonitor(formatHashtable(data));
		}
	}
	
	public void itemStateChanged(ItemEvent e) {
	    Object source = e.getItemSelectable();

	    if (source == counterOnBox) {
	        onSwitchCounter(true);
	    } 

	    if (e.getStateChange() == ItemEvent.DESELECTED)
	    	onSwitchCounter(false);
	  
	}
	
	/**
	 * Performs publish of data entered by user
	 */
	protected void onFaultManagerPublish(String namespace, String topic, GEMOMData data) {
		
		if (topic == null || topic.equalsIgnoreCase("")) {
			return;
		}
		if (VOLUMETRY_TEST_TOPIC.equalsIgnoreCase(topic)) {
			startVolumetryTest(topic);
		} else {
			
			// getGEMOMBrokerInterface().publish(this, topic, data, null);
			getGEMOMBrokerInterface().publish(null, namespace, topic, data,
					null, null);
			
			printLineInAllSubMonitor(getTimeAsString() + ": Publishing on " + namespace+
					"@/"+topic
					+ " , data:");
			printLineInAllSubMonitor(formatHashtable(data));
		}
	}
	
	/**
	 * Performs subscribe operation on topic entered by user
	 */
	
	protected void onSubscribe() {
		String namespace = m_namespaceSubscribeTopicField.getText();
		String topic = m_subscribeTopicField.getText();
		if (topic == null || topic.equalsIgnoreCase("")) {
			return;
		}
		GEMOMClientData clientData = new GEMOMClientData();
		clientData.put(topic + "_CLIENT_DATA_KEY", topic
				+ "_CLIENT_DATA_VALUE_" + (int) (Math.random() * 1000));
		getGEMOMBrokerInterface().subscribeOnTopic(this, namespace, topic,
				clientData, null);

		printLineInMonitor(getTimeAsString() + ": Subscribing on topic: "
				+ topic + " with clientData:");
		printLineInMonitor(formatHashtable(clientData));
	}
	
	protected void onSubscribe(String namespace, String topic) {
		//String namespace = namespaceField.getText();
		//String topic = topicField.getText();
		if (topic == null || topic.equalsIgnoreCase("")) {
			return;
		}
		GEMOMClientData clientData = new GEMOMClientData();
		clientData.put(topic + "_CLIENT_DATA_KEY", topic
				+ "_CLIENT_DATA_VALUE_" + (int) (Math.random() * 1000));
		getGEMOMBrokerInterface().subscribeOnTopic(this, namespace, topic,
				clientData, null);

		printLineInMonitor(getTimeAsString() + ": Subscribing on topic: "
				+ topic + " with clientData:");
		printLineInMonitor(formatHashtable(clientData));
	}
	
	/**
	 * Performs subscribe operation on topic entered by user
	 */
	protected void onUnSubscribe(String namespace, String topic) {
		//String namespace = m_namespaceSubscribeTopicField.getText();
		//String topic = m_subscribeTopicField.getText();
		if (topic == null || topic.equalsIgnoreCase("")) {
			return;
		}
		GEMOMClientData clientData = new GEMOMClientData();
		clientData.put(topic + "_CLIENT_DATA_KEY", topic
				+ "_CLIENT_DATA_VALUE_" + (int) (Math.random() * 1000));
		getGEMOMBrokerInterface().unsubscribeFromTopic(this, namespace, topic,
				clientData, null);

		printLineInMonitor(getTimeAsString() + ": Unsubscribing from topic: "
				+ topic + " with clientData:");
		printLineInMonitor(formatHashtable(clientData));
	}

	protected void onRename() {
		getGEMOMBrokerInterface().renameTopic(this,
				m_namespaceRenameTopicField.getText(),
				m_renameTopicField.getText(), m_newTopicField.getText(), null,
				null);
	}

	private void onMoveTopic() {
		getGEMOMBrokerInterface().moveTopic(this,
				m_sourceNamespaceMoveTopicField.getText(),
				m_destinationNamespaceMoveTopicField.getText(),
				m_moveTopicField.getText(), null, null);
	}

	protected void onDelete() {
		getGEMOMBrokerInterface().deleteTopic(this,
				m_namespaceDeleteTopicField.getText(),
				m_deleteTopicField.getText(), null, null);
	}

	protected void onNamespaceRename() {
		getGEMOMBrokerInterface().renameNamespace(this,
				m_namespaceRenameField.getText(),
				m_namespaceNewField.getText(), null, null);
	}

	private void onNamespaceMove() {
		getGEMOMBrokerInterface().moveNamespace(this,
				m_namespaceMoveField.getText(),
				m_namespaceMoveDestinationField.getText(), null, null);
	}

	protected void onNamespaceDelete() {
		getGEMOMBrokerInterface().deleteNamespace(this,
				m_namespaceDeleteField.getText(), null, null);
	}
	
	public void initSubscribe() {
		
		printLineInMonitor(getTimeAsString() + ": Initializing Auto-Subscriber");
		
		if(subscription != null && subscription.getSize() > 0){
			Enumeration nss  = subscription.getAllNamespace().keys();
			while(nss.hasMoreElements()){
				String ns = nss.nextElement().toString();
				if (ns != null || !ns.equalsIgnoreCase("")) {
					
					GEMOMClientData clientData = new GEMOMClientData();
					clientData.put(ns + "_CLIENT_DATA_KEY", ns
							+ "_CLIENT_DATA_VALUE_" + (int) (Math.random() * 1000));
					getGEMOMBrokerInterface().subscribeOnNamespace(this, ns,
							clientData, null);
					printLineInMonitor(getTimeAsString() + ": Scribing on namespace: "
							+ ns + " with clientData:");
					printLineInMonitor(formatHashtable(clientData));
				}       
			}	
		}
		
		updateTree();
		
		printLineInMonitor(getTimeAsString() + ": Auto-Subscriber initialized");
	}
	
	protected void onNamespaceSubscribe() {
		String namespace = m_namespaceSubscribeField.getText();
		debug("onNamespaceSubscribe " + namespace);
		if (namespace == null || namespace.equalsIgnoreCase("")) {
			return;
		}
		GEMOMClientData clientData = new GEMOMClientData();
		clientData.put(namespace + "_CLIENT_DATA_KEY", namespace
				+ "_CLIENT_DATA_VALUE_" + (int) (Math.random() * 1000));
		getGEMOMBrokerInterface().subscribeOnNamespace(this, namespace,
				clientData, null);

		printLineInMonitor(getTimeAsString() + ": Subscribing on namespace: "
				+ namespace + " with clientData:");
		printLineInMonitor(formatHashtable(clientData));

		// TODO: delete later, this is just temporary until subscribeOnNamespace
		// in psproxy is finished
		// String FS = "\034";
		// ((GEMOMBrokerInterfaceImpl) getGEMOMBrokerInterface())
		// .onNamespaceUpdate("__DIR" + FS + namespace + FS + "/n1/n2/t1"
		// + FS + "/n3/n4/t2");
	}

	protected void onNamespaceSubscribe(String namespace) {
		//String namespace = m_namespaceSubscribeField.getText();
		//debug("onNamespaceSubscribe " + namespace);
		if (namespace == null || namespace.equalsIgnoreCase("")) {
			return;
		}
		GEMOMClientData clientData = new GEMOMClientData();
		clientData.put(namespace + "_CLIENT_DATA_KEY", namespace
				+ "_CLIENT_DATA_VALUE_" + (int) (Math.random() * 1000));
		getGEMOMBrokerInterface().subscribeOnNamespace(this, namespace,
				clientData, null);

		printLineInMonitor(getTimeAsString() + ": Subscribing on namespace: "
				+ namespace + " with clientData:");
		printLineInMonitor(formatHashtable(clientData));

		// TODO: delete later, this is just temporary until subscribeOnNamespace
		// in psproxy is finished
		// String FS = "\034";
		// ((GEMOMBrokerInterfaceImpl) getGEMOMBrokerInterface())
		// .onNamespaceUpdate("__DIR" + FS + namespace + FS + "/n1/n2/t1"
		// + FS + "/n3/n4/t2");
	}
	

	protected void onNamespaceUnSubscribe(String namespace) {
		if (namespace == null || namespace.equalsIgnoreCase("")) {
			return;
		}
		GEMOMClientData clientData = new GEMOMClientData();
		clientData.put(namespace + "_CLIENT_DATA_KEY", namespace
				+ "_CLIENT_DATA_VALUE_" + (int) (Math.random() * 1000));
		getGEMOMBrokerInterface().unsubscribeFromNamespace(this, Util.addSlash(namespace),
				clientData, null);

		printLineInMonitor(getTimeAsString() + ": Unsubscribing from namespace: "
				+ namespace + " with clientData:");
		printLineInMonitor(formatHashtable(clientData));

		// TODO: delete later, this is just temporary until subscribeOnNamespace
		// in psproxy is finished
		// String FS = "\034";
		// ((GEMOMBrokerInterfaceImpl) getGEMOMBrokerInterface())
		// .onNamespaceUpdate("__DIR" + FS + namespace + FS + "/n1/n2/t1"
		// + FS + "/n3/n4/t2");

	}

	public boolean update(String namespace, String topic,
			GEMOMMessageType messageType, GEMOMData data,
			GEMOMClientData clientData) {

		namespace = Util.stripSlash(namespace);
		if(!m_publishToSystemOut){
		
		    // Print all updates on topics
			/*
	        printLineInAllSubMonitor(getTimeAsString() + ": Update on topic@Namespace = " + 
		    topic+"@/"+namespace+ " messageType: " + messageType + " with data:");
		    printLineInAllSubMonitor(formatHashtable(data));
		    printLineInAllSubMonitor("and client data:");
		    printLineInAllSubMonitor(formatHashtable(clientData)+"\n");
		    */

		
		    // See what's there in sub monitors by selecting namespace/topic.
		    if (shouldPrintUpdateInMonitor(topic) && isUserSelectedUpdate(namespace, topic, updateCode)) {
			    printLineInSubMonitor(getTimeAsString() + ": Update on topic@Namespace = " + 
					    topic+"@/"+namespace+ " messageType: " + messageType + " with data:");
			    printLineInSubMonitor(formatHashtable(data)+"\n");
			    //printLineInSubMonitor("and client data:");
			    //printLineInSubMonitor(formatHashtable(clientData));
		    }
		}
		else{
			System.out.println(namespace);
			System.out.println(topic);
			printGEMOMData(data);
		}

		m_updateCounter++;
		// if ((m_updateCounter % m_volumetryTestPublishCount) == 0
		// || (m_updateCounter % 1000) == 0) {
		// printLineInMonitor(getTimeAsString() + ": Update no. "
		// + m_updateCounter + " on topic " + topic + " with data");
		// printLineInMonitor(formatHashtable(data));
		// printLineInMonitor("and client data:");
		// printLineInMonitor(formatHashtable(clientData));
		// }

		return true;
	}

	private boolean shouldPrintUpdateInMonitor(String topic) {
		return !VOLUMETRY_TEST_TOPIC.equals(topic)
				|| (VOLUMETRY_TEST_TOPIC.equals(topic) && m_showVolumetryMonitorMessages);
	}

	void printInMonitor(String msg) {
		m_monitorMainArea.append(msg);
	}

	void printLineInMonitor(String msg) {
		printInMonitor(msg);
		m_monitorMainArea.append("\n");
	}
	
	void printInSubMonitor(String msg) {
		m_monitorSubArea.append(msg);
	}

	void printLineInSubMonitor(String msg) {
		printInSubMonitor(msg);
		m_monitorSubArea.append("\n");
	}
	
	void printInAllSubMonitor(String msg) {
		m_monitorAllSubArea.append(msg);
	}

	void printLineInAllSubMonitor(String msg) {
		printInAllSubMonitor(msg);
		m_monitorAllSubArea.append("\n");
	}
	
	void printSubscriberMsgInMonitor(String msg){
	    
	}
	

	protected void startVolumetryTest(final String topic) {
		final GEMOMData data = new GEMOMData();
		for (int i = 0; i < 4; i++) {
			String fieldName = m_fieldNameFields[i].getText();
			if (fieldName.equalsIgnoreCase("")) {
				continue;
			}
			String fieldValue = m_fieldValueFields[i].getText();
			data.put(fieldName, fieldValue);
		}

		new Thread() {

			public void run() {

				long publishTime = 0;
				Date generalStart = new Date();
				printLineInMonitor(getTimeAsString()
						+ ": Starting volumetry test for "
						+ m_volumetryTestPublishCount + " iterations on topic "
						+ topic);

				for (int i = 0; i < m_volumetryTestPublishCount; i++) {
					// add random data so PSProxy.dll wouldn't filter data as it
					// was already
					// successfully published
					data.put("RandomData", "" + i);
					data
							.put(
									"FillerData",
									"1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890");

					// getGEMOMBrokerInterface().publish(GEMOMTestApp2.this,
					// topic, data, null);
					getGEMOMBrokerInterface().publish(null, "", topic, data,
							null, null);

					if (m_showVolumetryMonitorMessages)
						printLineInMonitor(getTimeAsString() + ": Publishing "
								+ data + " on " + topic);
				}
				printLineInMonitor(getTimeAsString()
						+ ": Total publish time in ms: " + publishTime
						+ " for " + m_volumetryTestPublishCount + " publishes.");
				printLineInMonitor(getTimeAsString()
						+ ": Average publish time in ms (per publish: "
						+ ((double) publishTime) / m_volumetryTestPublishCount);
				Date generalEnd = new Date();
				printLineInMonitor(getTimeAsString()
						+ ": Total time (publish and overhead) in ms: "
						+ (generalEnd.getTime() - generalStart.getTime())
						+ " for " + m_volumetryTestPublishCount + " publishes.");

			}
		}.start();
	}

	protected String getTimeAsString() {
		return m_sdf.format(new Date());
	}

	@Override
	public boolean updateNamespace(String namespace, String topic,
			String newName, GEMOMMessageType messageType,
			GEMOMClientData clientData) {

		if (messageType.equals(GEMOMMessageType.TOPIC_CREATE)) {
			printLineInMonitor(getTimeAsString() + ":topic " + topic + " created, subscribing to: " + namespace
					+ topic);
			getGEMOMBrokerInterface().subscribeOnTopic(this, namespace, topic,
					clientData, null);
			
			subscription.addTopic(namespace, topic);
			updateTree();
			
		}
		// uncomment below block if you want to unsubscribe when topic is
		// deleted from
		// a namespace

		// else if (messageType.equals(GEMOMMessageType.TOPIC_DELETE)) {
		// debug("topic " + topic + " deleted, unsubscribing from: "
		// + namespace + topic);
		// getGEMOMBrokerInterface().unsubscribeFromTopic(this, namespace,
		// topic, clientData, null);
		// }
		return true;
	}

	private void updateTree(){
		
		DefaultMutableTreeNode top = subscription.buildTreeNode();

		DefaultTreeModel tmodel=new DefaultTreeModel(top);

		tree.setModel(tmodel);

		expandAll(tree,new TreePath(top),true);
		
	}
	
	@Override
	public String getGEMOMClientName() {
		return this.getClass().getName();
	}

	protected GEMOMBrokerAdapter getGEMOMBrokerInterface() {
		if (m_broker == null) {
			m_broker = new GEMOMBrokerAdapterImpl();
			// no debug info as it gets console difficult to follow
			((GEMOMBrokerAdapterImpl) m_broker).setShouldPrintDebugInfo(false);
			//GEMOMParameters connectParameters = new GEMOMParameters();
			//boolean connected = m_broker.connect(getGEMOMClientName(), this,
			//		connectParameters, null, null);
			//if (!connected) {
			//	debug("ERROR: Couldn't connect to GEMOM broker");
			//}
		}
		return m_broker;
	}

	private void debug(String string) {
		System.out.println("GEMOMSysClientsListenerDemo "
				+ m_sdf.format(new Date()) + ": " + string);
	}
	
	protected void debug(Object o) {
		System.out.println(o);
	}


	protected void onOptionSubscribe(){
		String namespace = namespaceField.getText();
		String topic = topicField.getText();
		if (!namespace.equalsIgnoreCase("")){ 
			
			if (topic == null || topic.equalsIgnoreCase("")) {
				onNamespaceSubscribe(namespace);
				printLineInMonitor(getTimeAsString() + ": Manually subscribing on namespace: " + namespace);
				subscription.addNamespace(namespace);
				
				
			}
			else{
				onSubscribe(namespace, topic);
				printLineInMonitor(getTimeAsString() + ": Manually subscribing on topic@/namespace: " + topic + "@/" + namespace);
				subscription.addTopic(namespace, topic);
			}
			updateTree();
		}
	}

	protected void onOptionUnsubscribe(){
		
		 DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();

		    String rootName = tree.getModel().getRoot().toString();
		    
         if (node == null){
             return;
         }

         Object nodeInfo = node.getUserObject();
         // topic selected
         
         if(!node.isRoot()){
             if (node.isLeaf()){
         	    // topic is selected
         	    if (!node.getParent().toString().equalsIgnoreCase(rootName)){
                     String topicName = (String)nodeInfo;
                     String nsName = node.getParent().toString();
                     onUnSubscribe(nsName, topicName);
                     subscription.removeTopic(nsName, topicName);
         	    }
         	     //A particular namespace selected, and it has no children topics subscribed
         	    else{
             	    String nsName = (String)nodeInfo;
                 	onNamespaceUnSubscribe(nsName);
                 	subscription.removeNamespace(nsName);
         	    }
         	    return;
             }
             // a namespace is selected, and it has children topics which it needs to un-subscribe too
             else{
          	    String nsName = (String)nodeInfo;
          	    // get all topics in this namespace
          	    for(int i = 0; i < node.getChildCount(); i++){
          	    	TreeNode tempNode = node.getChildAt(i);
          	    	String tempTopic = tempNode.toString();
          	    	if(tempTopic != null)
          	    		onUnSubscribe(nsName, tempTopic);
          	    }
             	onNamespaceUnSubscribe(nsName);
             	// Remove one ns removes all topics below it
             	subscription.removeNamespace(nsName);
             
             }
         }
         //All namespace selected
         else{
         }
         

         updateTree();
	}

	
	private void expandAll(JTree tree, TreePath parent, boolean expand) {
		// Traverse children
		DefaultMutableTreeNode node = (DefaultMutableTreeNode)parent.getLastPathComponent();
		if (node.getChildCount() >= 0) {
			for (Enumeration e=node.children(); e.hasMoreElements(); ) {
				DefaultMutableTreeNode n = (DefaultMutableTreeNode)e.nextElement();
				TreePath path = parent.pathByAddingChild(n);
				expandAll(tree, path, expand);
			}
		}

		// Expansion or collapse must be done bottom-up
		if (expand) {
			tree.expandPath(parent);
		} else {
			tree.collapsePath(parent);
		}
	}
	
	protected void setUpdateSetting(boolean allNameSpace, String nsName, String topicName){
	    if(allNameSpace){
	    	updateCode = 0;
	    	updateStrings[0] = "";
	    	updateStrings[1] = "";
	    }
	    else if (nsName != null && !nsName.equalsIgnoreCase("")){
	    	if (topicName == null && topicName.equalsIgnoreCase("")){
	    	    updateCode = 1;
	    	    updateStrings[0] = nsName;
	    	    updateStrings[1] = topicName;
	    	}
	    	else{
	    		updateCode = 2;
	    	    updateStrings[0] = nsName;
	    	    updateStrings[1] = topicName;
	    	}
	    }
	}
	
	private boolean isUserSelectedUpdate(String namespace, String topic, int code){
		//printLineInSubMonitor("NS = "+namespace+" and topic = "+topic +" and code = "+code);
	    if(updateCode == 1 && updateStrings[0].equalsIgnoreCase(namespace)){
	    	return true;
	    }
	    if(updateCode == 2 && updateStrings[0].equalsIgnoreCase(namespace) && updateStrings[1].equalsIgnoreCase(topic)){
	        return true;
	    }
	    else
	    	return false;
	    
	}

	public static String formatHashtable(Hashtable ht) {
		return formatMap(ht, 0);
	}

	public static String formatMap(Map map) {
		return formatMap(map, 0);
	}

	public static String formatMap(Map map, int level) {
		StringBuffer sb = new StringBuffer();

		if (map != null) {
			Object[] keysArray = new Object[map.size()];

			Set keys = map.keySet();

			int i = 0;
			Iterator it = keys.iterator();
			while (it.hasNext()) {
				keysArray[i] = it.next();
				i++;
			}
			String leading = "";
			for (i = 0; i < level; i++) {
				leading += "\t";
			}
			if (keysArray != null && keysArray.length > 0
					&& keysArray[0] instanceof Comparable) {
				Arrays.sort(keysArray);
			}

			for (i = 0; i < keysArray.length; i++) {
				if (map.get(keysArray[i]) instanceof Map) {
					sb.append(leading + keysArray[i] + " =\n"
							+ formatMap((Map) map.get(keysArray[i]), level + 1)
							+ "\n");

				} else {
					sb.append(leading + keysArray[i] + " = "
							+ map.get(keysArray[i]) + "\n");
				}
			}
		} else {
			sb.append("null");
		}

		return sb.toString();
	}
	
	private static void printGEMOMData(Map map) {
	
		if (map != null) {
			Object[] keysArray = new Object[map.size()];

			Set keys = map.keySet();

			int i = 0;
			Iterator it = keys.iterator();
			while (it.hasNext()) {
				keysArray[i] = it.next();
				i++;
			}
			if (keysArray != null && keysArray.length > 0
					&& keysArray[0] instanceof Comparable) {
				Arrays.sort(keysArray);
			}

			for (i = 0; i < keysArray.length; i++) {
				System.out.println(keysArray[i]);
				System.out.println(map.get(keysArray[i]));
			}
		} else {
		}

	}
}

